package com.anivia.system.auth.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.anivia.common.core.enums.DataScopeEnum;
import com.anivia.common.core.enums.DesensitizedTypeEnum;
import com.anivia.common.core.model.dto.BasePageDTO;
import com.anivia.common.core.model.vo.PageVO;
import com.anivia.common.core.util.AssertUtil;
import com.anivia.common.core.util.BeanUtil;
import com.anivia.common.web.config.tenant.TenantContext;
import com.anivia.system.auth.mapper.RoleInfoMapper;
import com.anivia.system.auth.model.dto.RoleAddOrUpdateDTO;
import com.anivia.system.auth.model.entity.RoleFieldDesensitizationDO;
import com.anivia.system.auth.model.entity.RoleInfoDO;
import com.anivia.system.auth.model.entity.RoleResourceInfoDO;
import com.anivia.system.auth.model.entity.UserInfoDO;
import com.anivia.system.auth.model.vo.ResourceInfoVO;
import com.anivia.system.auth.model.vo.RoleInfoVO;
import com.anivia.system.auth.service.IRoleFieldDesensitizationService;
import com.anivia.system.auth.service.IRoleInfoService;
import com.anivia.system.auth.service.IRoleResourceInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色 服务实现类
 * </p>
 *
 * @author wangj
 */
@Service
public class RoleInfoServiceImpl extends ServiceImpl<RoleInfoMapper, RoleInfoDO> implements IRoleInfoService {
    @Resource
    private IRoleFieldDesensitizationService roleFieldDesensitizationService;
    @Resource
    private IRoleResourceInfoService resourceInfoService;

    @Override
    @Transactional
    public void saveOrUpdate(RoleAddOrUpdateDTO dto) {
        // 检查名称是否存在
        boolean existsName = this.lambdaQuery().eq(RoleInfoDO::getName, dto.getName()).ne(dto.getId() != null, RoleInfoDO::getId, dto.getId()).exists();
        AssertUtil.isFalse(existsName, "名称已存在");

        RoleInfoDO roleInfoDO = null;
        if (dto.getId() == null) {
            roleInfoDO = BeanUtil.newBean(dto, RoleInfoDO.class);
        } else {
            roleInfoDO = this.getById(dto.getId());
            AssertUtil.notNull(roleInfoDO, "角色不存在");
            BeanUtil.copyProperties(dto, roleInfoDO);
        }
        this.saveOrUpdate(roleInfoDO);

        // 1.处理角色-脱敏字段关系
        // 删除旧的
        LambdaQueryWrapper<RoleFieldDesensitizationDO> eq = new LambdaQueryWrapper<RoleFieldDesensitizationDO>().eq(RoleFieldDesensitizationDO::getRoleId, roleInfoDO.getId());
        roleFieldDesensitizationService.remove(eq);
        // 保存新的
        if (CollUtil.isNotEmpty(dto.getDesensitizationField())) {
            RoleInfoDO finalRoleInfoDO = roleInfoDO;
            List<RoleFieldDesensitizationDO> list = dto.getDesensitizationField().stream().map(type -> {
                RoleFieldDesensitizationDO roleFieldDesensitizationDO = new RoleFieldDesensitizationDO();
                roleFieldDesensitizationDO.setRoleId(finalRoleInfoDO.getId());
                roleFieldDesensitizationDO.setField(type);
                return roleFieldDesensitizationDO;
            }).collect(Collectors.toList());
            TenantContext.isIgnore();
            roleFieldDesensitizationService.saveBatch(list);
        }

        // 2.处理角色-资源-数据区权限关系
        // 删除旧的
        resourceInfoService.remove(new LambdaQueryWrapper<>());
        List<RoleAddOrUpdateDTO.ResourceItemVO> resourceItemList = dto.getPermission();
        List<RoleResourceInfoDO> resourceInfoList = resourceItemList.stream().map(item -> {
            RoleResourceInfoDO roleResourceInfoDO = new RoleResourceInfoDO();
            roleResourceInfoDO.setResourceId(item.getResourceId());
            roleResourceInfoDO.setDataScope(item.getDataScope());
            if (DataScopeEnum.CUSTOM_DEPT.equals(item.getDataScope())) {
                roleResourceInfoDO.setCustomDeptIds(item.getCustomDeptIds());
            }
            return roleResourceInfoDO;
        }).collect(Collectors.toList());
        resourceInfoService.saveBatch(resourceInfoList);
    }

    @Override
    public void delete(Integer id) {
        RoleInfoDO roleInfoDO = this.getById(id);
        AssertUtil.notNull(roleInfoDO, "角色不存在");
        // TODO 各种校验

        this.removeById(id);
    }

    @Override
    public RoleInfoVO details(Integer id) {
        // 查询角色基本信息
        RoleInfoDO roleInfo = this.getById(id);
        AssertUtil.notNull(roleInfo, "角色不存在");
        RoleInfoVO roleInfoVO = BeanUtil.newBean(roleInfo, RoleInfoVO.class);

        // 查询脱敏字段
        List<RoleFieldDesensitizationDO> list = roleFieldDesensitizationService.lambdaQuery().eq(RoleFieldDesensitizationDO::getRoleId, id).list();
        List<DesensitizedTypeEnum> desensitizedTypeList = list.stream().map(RoleFieldDesensitizationDO::getField).collect(Collectors.toList());
        roleInfoVO.setDesensitizationField(desensitizedTypeList);

        // 查询有权限的资源
        List<ResourceInfoVO> resources = resourceInfoService.resources(id);
        roleInfoVO.setResource(resources);
        return roleInfoVO;
    }

    @Override
    public PageVO<RoleInfoVO> page(BasePageDTO dto) {
        MPJLambdaWrapper<RoleInfoDO> wrapper = new MPJLambdaWrapper<RoleInfoDO>()
                .select(RoleInfoDO::getId, RoleInfoDO::getName, RoleInfoDO::getDescription, RoleInfoDO::getStatus, RoleInfoDO::getCreateTime, RoleInfoDO::getUpdateTime)
                .selectAs("a", UserInfoDO::getUserName, RoleInfoVO::getCreatorName)
                .selectAs("b", UserInfoDO::getUserName, RoleInfoVO::getUpdaterName)
                .selectCollection(RoleFieldDesensitizationDO.class, RoleInfoVO::getDesensitizationField, map -> map.result(RoleFieldDesensitizationDO::getField))
                .disableSubLogicDel()
                .leftJoin(RoleFieldDesensitizationDO.class, RoleFieldDesensitizationDO::getRoleId, RoleInfoDO::getId)
                .leftJoin(UserInfoDO.class, "a", UserInfoDO::getId, RoleInfoDO::getCreatorId)
                .leftJoin(UserInfoDO.class, "b", on ->
                        on.eq(UserInfoDO::getId, RoleInfoDO::getUpdaterId)
                );

        Page<RoleInfoVO> voPage = getBaseMapper().selectJoinPage(new Page<>(dto.getPage(), dto.getSize()), RoleInfoVO.class, wrapper);
        PageVO<RoleInfoVO> vo = new PageVO<>();
        vo.setRecords(voPage.getRecords());
        vo.setTotal((int) voPage.getTotal());
        return vo;
    }
}